/*
 * Copyright (c) 2015. For Intelligent Group.
 */
package com.intelligent.ispc.client.core.view.analysis.grr;

import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.intelligent.ispc.client.core.controller.GrrController;
import com.intelligent.ispc.client.core.modal.grr.ConfigModel;
import com.intelligent.ispc.client.core.modal.grr.FixViewDataModel;
import com.intelligent.ispc.client.core.modal.grr.ViewDataTableModel;
import com.intelligent.ispc.client.core.view.AbstractPanel;
import com.intelligent.ispc.client.core.view.analysis.grr.render.ViewDataTableCellRenderer;
import com.intelligent.ispc.client.ex.dynamictable.DyLoadTask;
import com.intelligent.ispc.client.ex.dynamictable.DyTableLoader;
import com.intelligent.ispc.client.ex.dynamictable.DyTablePanel;
import com.intelligent.ispc.client.utils.*;
import com.intelligent.ispc.common.utils.ResourceBundleUtils;
import com.intelligent.ispc.constant.AppConstant;
import com.intelligent.ispc.core.dto.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import javax.swing.*;
import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.table.TableColumnModel;
import java.awt.*;
import java.awt.event.*;
import java.util.*;
import java.util.List;

/**
 * Created by cherry on 16/9/7.
 */
@Component
public class ViewDataPanel extends AbstractPanel {

    @Autowired
    private GrrController grrController;
    private ViewDataTableModel checkViewDataTableModel;
    private ViewDataTableModel unCheckViewDataTableModel;
    private FixViewDataModel fixCheckViewDataModel;
    private FixViewDataModel fixUnCheckViewDataModel;

    private ConfigModel configModel;
    private GrrGroupDto currentGroup;

    private String filePath;
    private int itemCount = UIConstant.DEFAULT_ITEM_COUNT;
    private int initFlag = 0;
    private static final int FIX_COLUMN_COUNT = 5;
    private static final int PAGE_SIZE = 25;

    @Override
    public void initDataSource() {
        checkViewDataTableModel.initDigGrrNum();
        unCheckViewDataTableModel.initDigGrrNum();
    }

    @Override
    public void initView() {
        DefaultTableCellRenderer tcr = new DefaultTableCellRenderer();
        tcr.setHorizontalAlignment(SwingConstants.CENTER);

        JTable fixCheckTable = checkScrollPane.getFixedTable();
        fixCheckTable.setDefaultRenderer(Object.class, tcr);
        fixCheckTable.getTableHeader().setReorderingAllowed(false);

        JTable fixUnCheckTable = unCheckScrollPane.getFixedTable();
        fixUnCheckTable.setDefaultRenderer(Object.class, tcr);
        fixUnCheckTable.getTableHeader().setReorderingAllowed(false);

        JTable dataCheckTable = checkScrollPane.getDataTable();
        JTable dataUnCheckTable = unCheckScrollPane.getDataTable();
        dataCheckTable.setDefaultRenderer(Object.class, tcr);
        dataUnCheckTable.setDefaultRenderer(Object.class, tcr);
    }

    @Override
    @PostConstruct
    public void initComponents() {
        this.setBorder(BorderFactory.createEmptyBorder());
        submitBtn = new JButton("Submit");
        this.setLayout(new GridBagLayout());

        checkViewDataTableModel = new ViewDataTableModel();
        unCheckViewDataTableModel = new ViewDataTableModel();
        fixCheckViewDataModel = new FixViewDataModel();
        fixUnCheckViewDataModel = new FixViewDataModel();

        checkLoader = new DyTableLoader(checkViewDataTableModel, FIX_COLUMN_COUNT, PAGE_SIZE, DyTableLoader.COL, null);
        checkLoader.setFixedModel(fixCheckViewDataModel);
        unCheckLoader = new DyTableLoader(unCheckViewDataTableModel, FIX_COLUMN_COUNT, PAGE_SIZE, DyTableLoader.COL, null);
        unCheckLoader.setFixedModel(fixUnCheckViewDataModel);
        checkScrollPane = new DyTablePanel(checkLoader);
        unCheckScrollPane = new DyTablePanel(unCheckLoader);
        checkScrollPane.setBorder(BorderFactory.createEmptyBorder());
        unCheckScrollPane.setBorder(BorderFactory.createEmptyBorder());
        checkScrollPane.setBorder(BorderFactory.createTitledBorder("Checked Data"));
        unCheckScrollPane.setBorder(BorderFactory.createTitledBorder("UnChecked Data"));

        final Dimension checkScrollPaneSize = new Dimension(300, 400);
        final Dimension unCheckScrollPaneSize = new Dimension(300, 200);
        checkScrollPane.setPreferredSize(checkScrollPaneSize);
        unCheckScrollPane.setPreferredSize(unCheckScrollPaneSize);

        JPanel btnPanel = new JPanel();
        btnPanel.setLayout(new GridBagLayout());
        btnPanel.setBorder(BorderFactory.createEmptyBorder());
        btnPanel.add(new JLabel(), new GBC(0, 0).setFill(GBC.BOTH).setWeight(100, 100).setInsets(5, 0, 5, 0));
        btnPanel.add(submitBtn, new GBC(1, 0).setFill(GBC.BOTH).setWeight(5, 100).setInsets(5, 0, 5, 0));

        JSplitPane splitPane = new JSplitPane(JSplitPane.VERTICAL_SPLIT, false, checkScrollPane, unCheckScrollPane);
        splitPane.setBorder(BorderFactory.createEmptyBorder());
        mainScrollPane = new JScrollPane();
        final Dimension mainScrollPaneSize = new Dimension(700, 768);
        mainScrollPane.setPreferredSize(mainScrollPaneSize);
        mainScrollPane.setViewportView(splitPane);
        mainScrollPane.setBorder(BorderFactory.createEmptyBorder());

        this.add(btnPanel, new GBC(0, 0).setFill(GBC.BOTH));
        this.add(mainScrollPane, new GBC(0, 1).setFill(GBC.BOTH).setWeight(100, 100));
        initComponentsEvent();
    }

    /**
     * reset view data panel contains clear table, reset scrollBar location
     */
    public void resetViewDataPanel() {
        JScrollBar jsVB = mainScrollPane.getVerticalScrollBar();
        if (jsVB != null) {
            jsVB.setValue(0);
        }
        currentGroup = null;
        itemCount = UIConstant.DEFAULT_ITEM_COUNT;
        clearTable();
        this.repaint();
    }

    private void clearTable() {
        checkViewDataTableModel.setColumns(null);
        unCheckViewDataTableModel.setColumns(null);
        checkScrollPane.clearAndRefreshTables();
        unCheckScrollPane.clearAndRefreshTables();
    }

    /**
     * load check data table and unChecked data table
     */
    public void loadTable() {
        clearTable();
        loadCheckData();
        loadUncheckData();
    }

    /**
     * set render for fixedTable and fixUnCheckTable
     */
    public void setRender() {
        JTable fixedTable = checkScrollPane.getFixedTable();
        if (fixedTable.getColumnCount() >= 2) {
            ViewDataTableCellRenderer defineRenderer = new ViewDataTableCellRenderer(fixedTable);
            TableColumnModel model = fixedTable.getColumnModel();
            model.getColumn(0).setCellRenderer(defineRenderer);
            model.getColumn(1).setCellRenderer(defineRenderer);
        }

        JTable fixUnCheckTable = unCheckScrollPane.getFixedTable();
        if (fixUnCheckTable.getColumnCount() >= 2) {
            ViewDataTableCellRenderer defineRenderer = new ViewDataTableCellRenderer(fixUnCheckTable);
            TableColumnModel model = fixUnCheckTable.getColumnModel();
            model.getColumn(0).setCellRenderer(defineRenderer);
            model.getColumn(1).setCellRenderer(defineRenderer);
        }
    }

    private void loadCheckData() {
        GrrParamDto grrParamDto = new GrrParamDto();
        grrParamDto.setFilePath(filePath);
        initFlag = 0;

        DyLoadTask task = new DyLoadTask<GrrViewDataDto>() {
            @Override
            public List<GrrViewDataDto> load(int start, int end) {
                List<GrrViewDataDto> checkViewDatas = Lists.newArrayList();
                java.util.List<GrrViewDataDto> viewDataDtos = null;
                if (end > start) {
                    viewDataDtos = grrController.findGrrViewData(grrParamDto, currentGroup, start, end);
                }

                if (viewDataDtos != null) {
                    for (int i = 0; i < viewDataDtos.size(); i++) {
                        if (viewDataDtos.get(i).getCheck()) {
                            checkViewDatas.add(viewDataDtos.get(i));
                        }
                    }
                }

                if (!checkViewDatas.isEmpty()) {
                    String[] columns = getViewDataTbTitle(checkViewDatas);
                    checkViewDataTableModel.setColumns(columns);
                    if (initFlag == 0) {
                        fixCheckViewDataModel.setColumns(UIConstant.ANALYSIS_GRR_VIEWDATA_FIXCOLUMNS);
                        fixCheckViewDataModel.setOperatorAndTrial(configModel.getAppraiserCount(), configModel.getTrialCount());
                        fixCheckViewDataModel.setData(checkViewDatas);
                        fixCheckViewDataModel.setType("check");
                        checkLoader.initPageCount(itemCount);
                    }
                    initFlag++;
                } else {
                    checkViewDataTableModel.setColumns(null);
                }
                return checkViewDatas;
            }

            @Override
            public void onloaded() {
                setRender();
            }
        };
        checkLoader.setTask(task);
        checkScrollPane.loadData();
    }

    private void loadUncheckData() {
        GrrParamDto grrParamDto = new GrrParamDto();
        grrParamDto.setFilePath(filePath);
        initFlag = 0;

        DyLoadTask task = new DyLoadTask() {
            @Override
            public List<GrrViewDataDto> load(int start, int end) {
                List<GrrViewDataDto> unCheckViewDatas = Lists.newArrayList();
                java.util.List<GrrViewDataDto> viewDataDtos = grrController.findGrrViewData(grrParamDto, currentGroup, start, end);

                if (viewDataDtos != null) {
                    for (int i = 0; i < viewDataDtos.size(); i++) {
                        if (!viewDataDtos.get(i).getCheck()) {
                            unCheckViewDatas.add(viewDataDtos.get(i));
                        }
                    }
                }

                if (!unCheckViewDatas.isEmpty()) {
                    String[] columns = getViewDataTbTitle(unCheckViewDatas);
                    unCheckViewDataTableModel.setColumns(columns);

                    if (initFlag == 0) {
                        fixUnCheckViewDataModel.setColumns(UIConstant.ANALYSIS_GRR_VIEWDATA_FIXCOLUMNS);
                        fixUnCheckViewDataModel.setOperatorAndTrial(configModel.getAppraiserCount(), configModel.getTrialCount());
                        fixUnCheckViewDataModel.setData(unCheckViewDatas);
                        unCheckLoader.initPageCount(itemCount);
                    }
                    initFlag++;

                } else {
                    unCheckViewDataTableModel.setColumns(null);
                }
                return unCheckViewDatas;
            }

            @Override
            public void onloaded() {
                setRender();
            }
        };

        unCheckLoader.setTask(task);
        unCheckScrollPane.loadData();
    }

    private void initComponentsEvent() {
        checkScrollPane.getFixedTable().addMouseListener(new MouseAdapter() {
            public void mouseClicked(MouseEvent e) {
                if (e.getClickCount() == 1) {
                    checkViewClickedEvent(e);
                }
            }
        });

        unCheckScrollPane.getFixedTable().addMouseListener(new MouseAdapter() {
            public void mouseClicked(MouseEvent e) {
                if (e.getClickCount() == 1) {
                    unCheckViewClickedEvent(e);
                }
            }
        });

        submitBtn.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                fireSubmitBtnEvent();
            }
        });

        checkScrollPane.addComponentListener(new ComponentAdapter() {
            @Override
            public void componentResized(ComponentEvent e) {
                checkScrollPane.allResizeTable(true);
            }
        });
        unCheckScrollPane.addComponentListener(new ComponentAdapter() {
            @Override
            public void componentResized(ComponentEvent e) {
                unCheckScrollPane.allResizeTable(true);
            }
        });
    }

    public void setCurrentGroup(GrrGroupDto currentGroup) {
        this.currentGroup = currentGroup;
    }

    public void setFilePath(String filePath) {
        this.filePath = filePath;
    }

    public void setConfigModel(ConfigModel configModel) {
        this.configModel = configModel;
    }

    private void fireSubmitBtnEvent() {
        boolean flag = false;
        GrrParamDto paramDto = new GrrParamDto();
        paramDto.setFilePath(filePath);

        flag = checkViewData(paramDto);
        if (flag) {
            submitBtn.setCursor(new java.awt.Cursor(Cursor.WAIT_CURSOR));
            grrController.updateViewDatas(paramDto, currentGroup);
            ApplicationBeanUtils.getBean(AnalysisPanel.class).loadSummary();
            loadTable();
            submitBtn.setCursor(new java.awt.Cursor(java.awt.Cursor.DEFAULT_CURSOR));
        } else {
            AppMessageFactory.showErrorDialog(ResourceBundleUtils.getString(ExceptionMessages.EXCEPTION_GRR_NOT_MATCH_ADD_REMOVE));
        }
    }

    private String[] getViewDataTbTitle(java.util.List<GrrViewDataDto> viewDatas) {

        String[] columnsBefore = UIConstant.ANALYSIS_GRR_VIEWDATA_FIXCOLUMNS;
        java.util.List<KeyValueDto> colValueDtos = Lists.newArrayList();
        if (viewDatas != null && !viewDatas.isEmpty()) {
            colValueDtos = viewDatas.get(0).getColValueDtoList();
        }
        int colValueSize = 0;
        if (!colValueDtos.isEmpty()) {
            colValueSize = colValueDtos.size();
        }
        String[] columnsAfter = new String[colValueSize];
        for (int i = 0; i < colValueSize; i++) {
            columnsAfter[i] = colValueDtos.get(i).getKey();
        }

        String[] columns = ArrayUtils.concat(columnsBefore, columnsAfter);
        return columns;
    }

    private boolean checkViewData(GrrParamDto grrParamDto) {

        boolean flag = true;
        java.util.List<GrrViewDataDto> checkViewDatas = fixCheckViewDataModel.getData();
        java.util.List<GrrViewDataDto> unCheckViewDatas = fixUnCheckViewDataModel.getData();
        java.util.List<String> newIncludeIds = Lists.newArrayList();
        java.util.List<String> newExcludeIds = Lists.newArrayList();
        Map<String, Integer> partTypeMap = Maps.newHashMap();
        Map<String, Integer> partOperatorGroupMap = Maps.newHashMap();

        int partTypeCount = configModel.getPartCount();
        int appraiserCount = configModel.getAppraiserCount();
        int trialCount = configModel.getTrialCount();

        for (int i = 0; i < checkViewDatas.size(); i++) {
            if (checkViewDatas.get(i).getCheck()) {
                String partName = checkViewDatas.get(i).getPart();
                String operator = checkViewDatas.get(i).getOperator();
                String key = partName + AppConstant.GLOBAL_SEPARATOR + operator;

                if (!partTypeMap.containsKey(partName)) {
                    partTypeMap.put(partName, 1);
                } else {
                    int count = partTypeMap.get(partName);
                    partTypeMap.put(partName, ++count);
                }

                if (!partOperatorGroupMap.containsKey(key)) {
                    partOperatorGroupMap.put(key, 1);
                } else {
                    int count = partOperatorGroupMap.get(key);
                    partOperatorGroupMap.put(key, ++count);
                }
            } else {
                newExcludeIds.add(checkViewDatas.get(i).getId());
            }
        }

        for (int i = 0; i < unCheckViewDatas.size(); i++) {
            if (unCheckViewDatas.get(i).getCheck()) {
                String partName = unCheckViewDatas.get(i).getPart();
                String operator = unCheckViewDatas.get(i).getOperator();
                String key = partName + AppConstant.GLOBAL_SEPARATOR + operator;

                if (!partTypeMap.containsKey(partName)) {
                    partTypeMap.put(partName, 1);
                } else {
                    int count = partTypeMap.get(partName);
                    partTypeMap.put(partName, ++count);
                }

                if (!partOperatorGroupMap.containsKey(key)) {
                    partOperatorGroupMap.put(key, 1);
                } else {
                    int operatorCount = partOperatorGroupMap.get(key);
                    partOperatorGroupMap.put(key, ++operatorCount);
                }
                newIncludeIds.add(unCheckViewDatas.get(i).getId());
            }
        }
        grrParamDto.setNewIncludeIds(newIncludeIds);
        grrParamDto.setNewExcludeIds(newExcludeIds);

        int count = 0;
        for (Map.Entry<String, Integer> entry : partTypeMap.entrySet()) {
            if (entry.getValue() != appraiserCount * trialCount) {
                flag = false;
                return flag;
            }
            count++;
        }

        if (count != partTypeCount) {
            flag = false;
            return flag;
        }

        if (AppConstant.GRR_MODEL_SLOT.equals(configModel.getSchema())) {
            String dimension = currentGroup.getDimensionValue();
            String[] dimensions = dimension.split(",");
            Map<String, Integer> dimensionMap = Maps.newHashMap();
            for (String var : dimensions) {
                if (!dimensionMap.containsKey(var)) {
                    dimensionMap.put(var, 1);
                } else {
                    int demensionCount = dimensionMap.get(var);
                    dimensionMap.put(var, ++demensionCount);
                }
            }

            for (Map.Entry<String, Integer> entry : partOperatorGroupMap.entrySet()) {
                String operator = entry.getKey().split(AppConstant.GLOBAL_SEPARATOR)[1];
                int operatorCountInStrategy = dimensionMap.get(operator);
                if (entry.getValue() != appraiserCount * operatorCountInStrategy) {
                    flag = false;
                    return flag;
                }
            }
        }
        return flag;
    }

    private void checkViewClickedEvent(MouseEvent e) {
        JTable table = checkScrollPane.getFixedTable();
        int columnIndex = table.columnAtPoint(e.getPoint());
        int rowIndex = table.rowAtPoint(e.getPoint());
        Object value = table.getValueAt(rowIndex, columnIndex);
        if (columnIndex == 0) {
            if (value == null) {
                fixCheckViewDataModel.setGroupCheckValue(false, rowIndex);
            } else if (Boolean.valueOf(value.toString())) {
                fixCheckViewDataModel.setGroupCheckValue(false, rowIndex);
            } else {
                fixCheckViewDataModel.setGroupCheckValue(true, rowIndex);
            }
        } else if (columnIndex == 1) {
            if (value == null) {
                fixCheckViewDataModel.setCheckValue(false, rowIndex);
            } else if (Boolean.valueOf(value.toString())) {
                fixCheckViewDataModel.setCheckValue(false, rowIndex);
            } else {
                fixCheckViewDataModel.setCheckValue(true, rowIndex);
            }
        }
    }

    private void unCheckViewClickedEvent(MouseEvent e) {
        JTable table = unCheckScrollPane.getFixedTable();
        int columnIndex = table.columnAtPoint(e.getPoint());
        int rowIndex = table.rowAtPoint(e.getPoint());
        if (columnIndex == 0) {
            if (table.getValueAt(rowIndex, columnIndex) == null) {
                fixUnCheckViewDataModel.setGroupCheckValue(false, rowIndex);
            }
            if (((Boolean) table.getValueAt(rowIndex, columnIndex)).booleanValue()) {
                fixUnCheckViewDataModel.setGroupCheckValue(false, rowIndex);
            } else {
                fixUnCheckViewDataModel.setGroupCheckValue(true, rowIndex);
            }
        } else if (columnIndex == 1) {
            if (table.getValueAt(rowIndex, columnIndex) == null) {
                fixUnCheckViewDataModel.setCheckValue(false, rowIndex);
            }
            if (Boolean.valueOf(table.getValueAt(rowIndex, columnIndex).toString())) {
                fixUnCheckViewDataModel.setCheckValue(false, rowIndex);
            } else {
                fixUnCheckViewDataModel.setCheckValue(true, rowIndex);
            }
        }
    }


    public JButton getSubmitBtn() {
        return submitBtn;
    }

    public void setItemCount(int itemCount) {
        this.itemCount = itemCount;
    }

    private JScrollPane mainScrollPane;
    private DyTablePanel checkScrollPane;
    private DyTableLoader checkLoader;
    private DyTablePanel unCheckScrollPane;
    private DyTableLoader unCheckLoader;
    private JButton submitBtn;
}

